#pragma once
#include <cstdint>
#include <sys/epoll.h>
#include<unordered_map>
#include<iostream>
#include<memory>
#include"Epoller.hpp"
#include "Connection.hpp"


using namespace EpollerModule;
using connection_t = std::shared_ptr<Connection>; 

//组织
class Reactor
{
    const static int event_num = 64;
public:
    Reactor():_isrunning(false),_epoller(std::make_unique<Epoller>())
    {
        _epoller->Init();
    }
    
    //插入新连接
    void InsertConnection(connection_t con)
    {
        auto iter = _connections.find(con->Fd());
        if(iter == _connections.end())
        {
            //1.将连接放到connsection中进行管理
            _connections.insert(std::make_pair(con->Fd(),con));
            //2.将连接写透到内核中，插入到红黑树
            _epoller->Add(con->Fd(), con->GetEvents());
            //3.设置关联关系，让connection回指回当前对象
            con->SetOwner(this);
        }
    }
    //连接是否合法
    bool IsConnectionExits(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }

    //使能读写，管理读写关心
    void EnableReadWrite(int sockfd, bool readable, bool writeable)
    {
        if (IsConnectionExits(sockfd))
        {
            // 修改用户层connection的事件
            uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
            _connections[sockfd]->SetEvents(events);
            // 写透到内核中
            _epoller->Update(sockfd, _connections[sockfd]->GetEvents());
        }
    }

    //异常去除
    void DelConnection(int sockfd)
    {
        if(IsConnectionExits(sockfd))
        {
            //1.解除内核对异常fd的关心
            _epoller->Delete(sockfd);
            //2.关闭文件描述符
            _connections[sockfd]->Close(sockfd);
            //3.从_connections移除
            _connections.erase(sockfd);
        }
    }
    
    //派发任务
    void DisPatcher(int n)
    {
        //派发就绪的任务
        for(int i = 0;i < n;i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;

            if((revents & EPOLLERR) || (revents & EPOLLHUP))
                revents = (EPOLLIN | EPOLLOUT);//异常事件转化为读写事件

            //有些事件是读写事件所以要进行就绪判断和合法判断，防止处理其中一个事件后将文件描述符关闭
            if((revents & EPOLLIN) && IsConnectionExits(sockfd))
            {
                _connections[sockfd]->Recver();
            }
            if((revents & EPOLLOUT) && IsConnectionExits(sockfd))
            {
                _connections[sockfd]->Sender();
            }
        }
    }
    //循环一次
    void LoopOnce(int timeout)
    {
        //获取就绪的任务和数量
        int n = _epoller->Wait(_revs,  event_num,timeout);
        DisPatcher(n);
    }
    //路由
    void Loop()
    {
        _isrunning = true;
        int timeout = -1;
        while(_isrunning)
        {
            LoopOnce(timeout);
        }
        _isrunning = false;
    }
    ~Reactor()
    {}
    
private:
    std::unique_ptr<Epoller> _epoller;//必须要初始化
    std::unordered_map<int, connection_t> _connections;//所有的链接
    bool _isrunning;
    struct epoll_event _revs[event_num];
};
